/*
 * @(#)CommonIndexValueTag.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.dms.taglib;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;

import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ResponseUtils;

import com.dcivision.dms.DmsOperationConstant;
import com.dcivision.dms.bean.DmsDefaultProfileSetting;
import com.dcivision.dms.core.AutoSuggestIndexValueManager;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.AutoCompleteInputBoxManagerFactory;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.Utility;
import com.dcivision.framework.taglib.TagUtil;
import com.dcivision.framework.taglib.html.AutoCompleteInputBoxTag;
import com.dcivision.framework.taglib.html.DatepickerTag;
import com.dcivision.framework.taglib.html.FloatTag;
import com.dcivision.framework.taglib.html.FormTag;
import com.dcivision.framework.taglib.html.IntegerTag;
import com.dcivision.framework.taglib.html.OptionsTag;
import com.dcivision.framework.taglib.html.SelectTag;
import com.dcivision.framework.taglib.html.TextTag;

/**
 * Custom tag that print out the common index value, either in view mode
 * or edit mode, depends on the requesting mode of the page.
 *
 * @author  Lun Au
 * @company DCIVision Limited
 * @date    2007-05-04
 * @version $Revision: 1.1.2.13 $
 * @see     com.dcivision.framework.taglib.html.TextTag
 * @see     com.dcivision.framework.taglib.html.SelectTag
 * @see     com.dcivision.framework.taglib.html.DatepickerTag
 * @see     com.dcivision.framework.taglib.html.AutoCompleteInputBoxTag
 * 
 */
public class CommonIndexValueTag extends TextTag {
  
  public static final String DEFAULT_FIELD_SIZE = "40";
  
  public static final String DEFAULT_FIELD_MAX_LENGH = "255";
 
  private FormTag formTag = null;
  
  private CommonIndexTag indexTag = null;
  
  private boolean isReferenceNoField = false;
  private boolean isDescriptionField = false;
  
  /**
   * Starts to render the common index value, for requirements of display, refer EIP-2703
   * 1. If in CREATE mode, display as editable text field/auto complete box/selection box with default value<br>
   * 2. If in EDIT mode, display as editable text field/auto complete box/selection box without default value<br>
   * 3. If in VIEW mode, display text only and a hidden field
   * @see javax.servlet.jsp.tagext.TagSupport#doStartTag()
   */
  public int doStartTag() throws JspException {
    indexTag = (CommonIndexTag)findAncestorWithClass(this, CommonIndexTag.class);
    formTag = (FormTag)findAncestorWithClass(indexTag, FormTag.class);
    DmsDefaultProfileSetting setting = (DmsDefaultProfileSetting)pageContext.getAttribute(indexTag.getId());

    // TODO Better handle the field size, handle all text/datepicker/selection,etc
    this.setMaxlength(DEFAULT_FIELD_MAX_LENGH);
    this.setSize(DEFAULT_FIELD_SIZE);
    
    this.setParent(formTag);
    
    isReferenceNoField = indexTag.isIncludeSystemProfile()
        && ((!indexTag.isShowProfileAsc() && indexTag.getIndex() == 0)
            || (indexTag.isShowProfileAsc() && indexTag.getIndex() == (Integer.parseInt(indexTag.getLength()) - 2)));
    
    isDescriptionField = indexTag.isIncludeSystemProfile()
    && ((!indexTag.isShowProfileAsc() && indexTag.getIndex() == 1)
        || (indexTag.isShowProfileAsc() && indexTag.getIndex() == (Integer.parseInt(indexTag.getLength()) - 1)));
    
    if (isReferenceNoField) {
      setProperty("referenceNo");
    } else if (isDescriptionField) {
      setProperty("description");
    } else {
      setProperty("userDef"+(setting.getID()));
    }

    // setValue should be after setProperty because it will retrieve property from bean
    this.setValue(determineIndexValue(setting));
    
/*
    if (!Utility.isEmpty(formTag)) {
    log.debug("Rendering the common index: ");
    log.debug("formBeanName=" + formTag.getBeanName());
    log.debug("documentBeanName=" + indexTag.getDocumentBean());
    log.debug("navMode=" + RequestUtils.lookup(pageContext, formTag.getBeanName(), "navMode", null));
    log.debug("opMode=" + RequestUtils.lookup(pageContext, formTag.getBeanName(), "opMode", null));
    log.debug("fieldName=" + setting.getFieldName());
    log.debug("fieldType=" + setting.getFieldType());
    log.debug("propertyName=" + this.getProperty());
    log.debug("fieldValue=" + RequestUtils.lookup(pageContext, indexTag.getDocumentBean(), this.getProperty(), null));
    }
*/
    if (indexTag.isEnableDisplayFilter()) {
      if (isSelected2Show(setting)) {
        indexTag.setSkipCurrentBody(false);
      } else {
        indexTag.setSkipCurrentBody(true);
      }
    }
    //if fieldType is String and filled the defaultSelectValues should be considered selectionBox
    if(DmsDefaultProfileSetting.FIELD_TYPE_SELECT_DATABASE.equals(setting.getFieldType())
        ||DmsDefaultProfileSetting.FIELD_TYPE_SELECT_HARDCODE.equals(setting.getFieldType())
        ||(DmsDefaultProfileSetting.FIELD_TYPE_STRING.equals(setting.getFieldType())&&!Utility.isEmpty(setting.getDefaultSelectValues()))){
      ResponseUtils.write(pageContext, renderSelectionField(setting));
    }else{
      ResponseUtils.write(pageContext, renderTextField(setting));
    }
    // Should not return super.doStartTag() here
    // because all the rendering work should be completed by the above renderXXXField
    return Tag.SKIP_BODY;
  }
  
  protected boolean isSelected2Show(DmsDefaultProfileSetting setting)  {
    if (isSystemProfileFild() && (indexTag.getSystemSelectedDisplayIDs() == null)) {
      return false;
    }
    
    if (!isSystemProfileFild() && (indexTag.getCommonSelectedDisplayIDs() == null)) {
      return false;
    }
    
    if (isSystemProfileFild()) {
      for (int i = 0; i < indexTag.getSystemSelectedDisplayIDs().length; i++) {
        String currentID = indexTag.getSystemSelectedDisplayIDs()[i];
        if (Utility.isEmpty(currentID)) {
          break;
        }
        Integer selectedSystemID = Integer.valueOf(currentID);
        if (selectedSystemID.equals(setting.getID())) {
          return true;
        }      
      }
    } else {
      for (int i = 0; i < indexTag.getCommonSelectedDisplayIDs().length; i++) {
        String currentID = indexTag.getCommonSelectedDisplayIDs()[i];
        if (Utility.isEmpty(currentID)) {
          break;
        }
        Integer selectedCommonID = Integer.valueOf(currentID);
        if (selectedCommonID.equals(setting.getID())) {
          return true;
        }
      }
    }
    
    return false;
  }

  /**
   * Renders the String/Integer/Float/Date type
   * 
   * @param formTag The enclosing FormTag, which have navMode/opMode property 
   * @param indexTag The enclosing CommonIndexTag
   * @param setting The DmsDefaultProfileSetting bean representing this index
   * @return The rendered HTML code fragment
   * @throws JspException
   * @see FormTag
   * @see CommonIndexTag
   * @see DmsDefaultProfileSetting
   */
  public String renderTextField(DmsDefaultProfileSetting setting) throws JspException {
    TextTag textTag = new TextTag();
    if(DmsDefaultProfileSetting.FIELD_TYPE_DATE.equals(setting.getFieldType())){
      textTag = new DatepickerTag();
      if(DmsDefaultProfileSetting.FIELD_TYPE_DATE.equals(setting.getFieldType())
          && GlobalConstant.TRUE.equals(setting.getUseSystemDate()) && isShowDefaultValue()){
        ((DatepickerTag)textTag).setDefaultToday(true);
      }
    }else if(DmsDefaultProfileSetting.FIELD_TYPE_FLOAT.equals(setting.getFieldType())){
      textTag = new FloatTag();
    }else if(DmsDefaultProfileSetting.FIELD_TYPE_INTEGER.equals(setting.getFieldType())){
      textTag = new IntegerTag();
    }else if(DmsDefaultProfileSetting.FIELD_TYPE_STRING.equals(setting.getFieldType())){
      if(!this.getTextOnly()){
        if  (!Utility.isEmpty(setting.getValueSuggestFlag()) && setting.getValueSuggestFlag().equals("Y")) {
          // render the autocomplete box
          return renderAutoSuggestIndexValue ();
        }else{
          // render the editable selection box
          return renderAutoSuggestDefaultIndexValue (setting);
        }
      }else{
        textTag = new TextTag();
      }
    }
    textTag.setPageContext(pageContext);
    textTag.setParent(this.getParent());
    textTag.setProperty(this.getProperty());
    textTag.setName(this.indexTag.getDocumentBean());
    textTag.setValue(this.getValue());
    textTag.setMaxlength(this.getMaxlength());
    textTag.setSize(this.getSize());
    textTag.setTextOnly(this.getTextOnly());
    textTag.setStyleClass(getStyleClass());
    
    String content = TagUtil.renderTag(pageContext, textTag);
//log.debug(content);    
    return content;
  }
  
  /**
   * Renders the auto suggest entered index value for String type (ONLY)
   * 
   * @param formTag The enclosing FormTag, which have navMode/opMode property 
   * @param indexTag The enclosing CommonIndexTag
   * @param setting The DmsDefaultProfileSetting bean representing this index
   * @return The rendered HTML code fragment
   * @throws JspException
   * @see FormTag
   * @see CommonIndexTag
   * @see DmsDefaultProfileSetting
   * @see AutoCompleteInputBoxTag
   */
  public String renderAutoSuggestIndexValue() throws JspException {
    AutoCompleteInputBoxTag autoComplete = new AutoCompleteInputBoxTag();
    autoComplete.setPageContext(pageContext);
    autoComplete.setParent(this.getParent());
    autoComplete.setName(this.getProperty());
    autoComplete.setBoxType(AutoCompleteInputBoxManagerFactory.BOX_TYPE_INDEX_VALUE);
    autoComplete.setValue(this.getValue());
    autoComplete.setStyleClass(getStyleClass());
    autoComplete.setMaxlength(this.getMaxlength());
    autoComplete.setSize(this.getSize());
    autoComplete.setParameter(AutoSuggestIndexValueManager.FIELD_ID+":"+(indexTag.getIndex()+1));
    return TagUtil.renderTag(pageContext, autoComplete);
  }
  
  /**
   * Renders the floating combo box for pre-defined default values for String type (ONLY) 
   * 
   * @param formTag The enclosing FormTag, which have navMode/opMode property 
   * @param indexTag The enclosing CommonIndexTag
   * @param setting The DmsDefaultProfileSetting bean representing this index
   * @return The rendered HTML code fragment
   * @throws JspException
   * @see FormTag
   * @see CommonIndexTag
   * @see DmsDefaultProfileSetting
   */
  public String renderAutoSuggestDefaultIndexValue(DmsDefaultProfileSetting setting) throws JspException {
    String comboIdentifier = this.getProperty();
    TextTag comboTag = new TextTag();
    comboTag.setPageContext(pageContext);
    comboTag.setParent(this.getParent());
    comboTag.setProperty(this.getProperty());
    comboTag.setValue(this.getValue());
    comboTag.setMaxlength(this.getMaxlength());
    comboTag.setSize(this.getSize());
    comboTag.setTextOnly(false);
    comboTag.setOnkeydown("triggerFloatingCombo('myDummyLayer_"+comboIdentifier+"','"+comboIdentifier+"','"+comboIdentifier+"','myCombo_"+comboIdentifier+"','mySelectionBox_"+comboIdentifier+"')");
    String comboContent = TagUtil.renderTag(pageContext, comboTag);

    StringBuffer content = new StringBuffer(); 
    content.append("\n<div id=\"myDummyLayer_"+comboIdentifier+"\" style=\"position:relative;width:300px; z-index:"+(100-indexTag.getIndex()*2)+";\">");
    content.append("\n").append(comboContent);
    content.append("\n<input type=\"button\" style=\"background-image:url(../img/pref3/common/IconArrowDown.gif);background-repeat: no-repeat;background-position: 2px 2px;width:20px;height:22px\" onClick=\"triggerFloatingCombo('myDummyLayer_"+comboIdentifier+"','"+comboIdentifier+"','"+comboIdentifier+"','myCombo_"+comboIdentifier+"','mySelectionBox_"+comboIdentifier+"', true)\">");
    content.append("\n</div>");
    content.append("\n<div id=\"myCombo_"+comboIdentifier+"\" style=\"position:absolute;top:1px;left:0px;z-index:"+(99-indexTag.getIndex()*2)+";visibility:hidden;width:300px\">");
    content.append("\n<select id=\"mySelectionBox_"+comboIdentifier+"\" name=\"mySelectionBox_"+comboIdentifier+"\" style=\"width:274px\" onclick=\"fireSelection(this,true,null)\" onkeydown=\"fireSelection(this,false,null)\" onblur=\"hideFloatingCombo('myCombo_"+comboIdentifier+"')\" size=\"5\">");
    String defaultValues[] = setting.getDefaultSelectValues().split(DmsDefaultProfileSetting.DEFAULT_VALUES_SEPARATOR);
    for(int i=0;i<defaultValues.length;i++){
      content.append("\n<option value=\"\">").append(defaultValues[i]).append("</option>");
    }
    content.append("\n</select>");
    content.append("\n</div>");
    return content.toString();
  }
  
  /**
   * Renders the Select Menu from Database type
   * 
   * @param formTag The enclosing FormTag, which have navMode/opMode property 
   * @param indexTag The enclosing CommonIndexTag
   * @param setting The DmsDefaultProfileSetting bean representing this index
   * @return The rendered HTML code fragment
   * @throws JspException
   * @see FormTag
   * @see CommonIndexTag
   * @see DmsDefaultProfileSetting
   */
  public String renderSelectionField(DmsDefaultProfileSetting setting) throws JspException {
    SelectTag selectTag = new SelectTag();
    selectTag.setPageContext(pageContext);
    selectTag.setParent(this.getParent());
    selectTag.setProperty(this.getProperty());
    selectTag.setValue(this.getValue());
    selectTag.setTextOnly(this.getTextOnly());
    String[][] options = getOptions(setting);
    OptionsTag optionsTag = new OptionsTag();
    optionsTag.setPageContext(pageContext);
    optionsTag.setParent(selectTag);
    String[] values = null;
    //if fieldType is String and filled the defaultSelectValues 
    if(!Utility.isEmpty(setting.getDefaultSelectValues())) {
       values = setting.getDefaultSelectValues().split(";");
    }
    if(!Utility.isEmpty(values)&&!Utility.isEmpty(options)) {
      int j=0;
      String[][] endValues = new String[options.length+values.length][];
      for(int i=0;i<endValues.length;i++) {
        if(i<options.length) {
           endValues[i] = options[i]; 
        } else {
            endValues[i] = new String[] {values[j++],values[j++]};
         }
      }
      optionsTag.setStringArray(endValues);       
    } else if (!Utility.isEmpty(values)) {
      String[][] endValues = new String[values.length][];
      for (int i=0;i<endValues.length;i++) {
        endValues[i] = new String[] {null,values[i]};
      }
      optionsTag.setStringArray(endValues);
    }else {
      optionsTag.setStringArray(options);
    }    
    String content = TagUtil.renderSelectTag(pageContext, selectTag, optionsTag);
    log.debug(content.toString());
    return content.toString(); 
  }
  
  /**
   * Determines the value to be displayed in a specific index. The displaying logic follows:
   * 1. If in CREATE mode, display the default value (if any).
   * 2. Otherwise, show the value retrieve from the property of the documentBean specified in CommonIndexTag
   * 
   * @param formTag The enclosing FormTag, which have navMode/opMode property 
   * @param indexTag The enclosing CommonIndexTag
   * @param setting The DmsDefaultProfileSetting bean representing this index
   * @return The rendered HTML code fragment
   * @throws JspException
   * @see FormTag
   * @see CommonIndexTag
   * @see CommonIndexTag#documentBean
   * @see DmsDefaultProfileSetting
   */
  protected String determineIndexValue(DmsDefaultProfileSetting setting) throws JspException {
    // Refer to EIP-2333 for default value clarifications
    String indexValue = null;
    
    if (isShowDefaultValue()) {
      if (!DmsDefaultProfileSetting.FIELD_TYPE_DATE.equals(setting.getFieldType()) ||
          !GlobalConstant.TRUE.equals(setting.getUseSystemDate())) {
        indexValue = setting.getDefaultValue();
      }
      
      return indexValue;
    }
    
    Object obj = (RequestUtils.lookup(pageContext, indexTag.getDocumentBean(), this.getProperty(), null));
    if (!Utility.isEmpty(obj)) {
      indexValue = obj.toString();
    }

    return indexValue;
  }
  
  protected boolean isShowDefaultValue() throws JspException {
    if (Utility.isEmpty(formTag)) {
      return false;
    }
    
    String navMode = (String) RequestUtils.lookup(pageContext, formTag.getBeanName(), "navMode", null);
    boolean isShowDefaultValue = false;
    
    if (GlobalConstant.NAV_MODE_NEW.equals(navMode)) {
      isShowDefaultValue = true;
    }
    
    return isShowDefaultValue;
  }
  
  /**
   * Returns if it is editable or not based on navMode/opMode.
   * Logic to be implemented in this method (not passing through tag attribute)
   * 
   * @return Whether to display as view only mode
   * @see    com.dcivision.framework.web.AbstractActionForm#getNavMode()
   */
  public boolean getTextOnly(){
    try {
      if (Utility.isEmpty(formTag)) {
        return true;
      }
      
      String navMode = (String)RequestUtils.lookup(pageContext, formTag.getBeanName(), "navMode", null);
      String opMode = (String)RequestUtils.lookup(pageContext, formTag.getBeanName(), "opMode", null);
      // When creating or editing (edit index) a document
      if(GlobalConstant.NAV_MODE_NEW.equals(navMode) || GlobalConstant.NAV_MODE_EDIT.equals(navMode)){
        return false;
      }
      // When copying a document
      else if(!GlobalConstant.NAV_MODE_VIEW.equals(navMode) && DmsOperationConstant.COPY_OPERATION.equals(opMode)){
        return false;
      }      
      // When moving a document
      else if(!GlobalConstant.NAV_MODE_VIEW.equals(navMode) && DmsOperationConstant.MOVE_OPERATION.equals(opMode)){
    	return false;
      }
      // When creating reference file 
      else if(Utility.isEmpty(navMode) && DmsOperationConstant.CREATE_EMPTY_FILE.equals(opMode)){
        return false;
      }
      // When creating compound document
      else if(DmsOperationConstant.CREATE_COMPOUND_DOCUMENT.equals(navMode)){
        return false;
      }
      // When it is a refresh (due to select different folder/profile) when creating documents
      else if(GlobalConstant.OP_MODE_REFRESH.equals(opMode)){
        return false;
      }
    } catch (JspException exp) {
      log.error(exp.getMessage(), exp);
    }
    return true;
  }
  
  private String[][] getOptions(DmsDefaultProfileSetting setting) {
    SessionContainer sessionContainer = (SessionContainer)this.pageContext.getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    String options[][] = null;
    try {
      options = new com.dcivision.dms.core.DocumentOperationManager(sessionContainer, (java.sql.Connection)pageContext.getRequest().getAttribute(GlobalConstant.DB_KEY)).getOptionStringArray(setting);
    }catch(ApplicationException ae){
      log.error(ae.getMessage(), ae);
    }
    return options;
  }
  
  protected boolean isSystemProfileFild() {
    return (isReferenceNoField || isDescriptionField);
  }
  
  /**
   * The release method, clean up resources
   * 
   * @see javax.servlet.jsp.tagext.BodyTagSupport#release()
   */
  public void release() {
    formTag = null;
    indexTag = null;
    isReferenceNoField = false;
    isDescriptionField = false;
    super.release();
  }
  
  
}
